from logging import getLogger

from zope.interface import implements

from twisted.internet.defer import maybeDeferred

from twisted.scheduling.task import ScheduledCall

from meercat.job.interfaces import IScheduledJob



log = getLogger('meercat.job.scheduled')

class ScheduledJob(object):
    """ ScheduledJob is a base Job class for scheduled jobs. It handles 
    creating the ScheduledCall from the provided schedule, starts/stops the 
    ScheduledCall when the job is started or stopped, and passes status 
    information from the ScheduledCall as Job status. """
    
    implements(IScheduledJob)
    
    def __init__(self,schedule,f,*args,**kwargs):
        self._schedule = schedule
        self._f = f
        self._deferred = None
        self._factory = kwargs.setdefault('deferredFactory',maybeDeferred)
        self._error = None
        del kwargs['deferredFactory']
        
        self._call = ScheduledCall(self._generateDeferred,*args,**kwargs)
    
    def _generateDeferred(self, *args, **kwargs):
        d = self._factory(self._f, *args, **kwargs)
        d.addErrback(self._handleFailure)
        return d
        
    def __getstate__(self):
        """ Return the state dictionary for pickling """
        d = self.__dict__.copy()
        
        if '_call' in d:
            del d['_call']
        
        return d
    
    def start(self):
        """ """
        log.debug('%s.start()' % (str(self),))
        self._error = None
        self._deferred = self._call.start(self._schedule)
        self._deferred.addErrback(self._handleFailure)
        return self._deferred
    
    def _handleFailure(self, failure):
        log.error(str(failure))
        self._error = failure
        self.stop()
        return failure
    
    def stop(self):
        """ """
        log.debug('%s.stop()' % (str(self),))
        try:
            return self._call.stop()
        except AssertionError:
            return None
    
    def getScheduledCall(self):
        return self._call
    
    def getError(self):
        return self._error
    
    def isRunning(self):
        """ """
        return bool(self._call.running)
    
    def getStatus(self):
        """ """
        if self.isRunning():
            return u'Running'
        elif self.getError():
            return u'Stopped: %s' % (str(self.getError()),)
        else:
            return u'Stopped'